﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DiagrammInternalStructure.Exceptions;

namespace DiagrammInternalStructure
{
    /// <summary>
    /// Representation of Class
    /// </summary>
    public partial class ClassElement:AtomicInstance
    {
        private List<ConstructorField> m_constructors = new List<ConstructorField>();
        private List<ParameterField> m_parameters = new List<ParameterField>();
        private List<FunctionField> m_functions = new List<FunctionField>();

        private ClassElement m_base = null;

        private bool m_final = false;
        
        public ClassElement(string name, ProtectionType protection):base(name, protection)
        {            
                CheckingBasicTypes();
                m_base = ClassElement.Object;
                m_final = false;
        }

        public ClassElement(string name, ProtectionType protection, ClassElement baseClass)
        {            
                CheckingBasicTypes();
                if (baseClass != null && baseClass.m_final)
                {
                    throw new BaseClassCanNotHaveChildrenException();
                }
                else if (baseClass == null && name == "object" && ObjectsCounter.CurrentMaxIndex < 2)
                {
                    m_base = null;
                }
                else
                {
                    m_base = baseClass;
                }
                m_final = false;
                Name = name;
                Protection = protection;
        }

        #region manage constructors
        public bool AddConstructor(ConstructorField constructor)
        {
            CheckingBasicTypes(); 
            if (IsContainsConstructor(constructor))
            {
                return false;
            }
            else
            {
                m_constructors.Add(constructor);
                return true;
            }
        }

        public bool RemoveConstructor(ConstructorField constructor)
        {
            CheckingBasicTypes();
            return m_constructors.Remove(constructor);
        }
        #endregion
        
        #region manage parameters
        public bool AddParameter(ParameterField parameter)
        {
            if (IsContains<ParameterField>(parameter.Name))
            {
                return false;
            }
            else
            {
                m_parameters.Add(parameter);
                return true;
            }
        }

        public bool RemoveParameter(ParameterField parameter)
        {
            return m_parameters.Remove(parameter);
        }

        public bool RemoveParameter(string name)
        {
            ParameterField toRemove = null;
            foreach (ParameterField p in m_parameters)
            {
                if (p.Name == name)
                {
                    toRemove = p;
                    break;
                }
            }
            return RemoveParameter(toRemove);
        }
        #endregion

        #region manage methods

        #endregion

        public ConstructorField GerConstructorBySignature(FunctionSignature sign)
        {
            CheckingBasicTypes();
            foreach(ConstructorField cf in m_constructors)
            {
                if (cf.Signature.CompareTo(sign) == 1)
                {
                    return cf;
                }
            }
            return null;
        }

        public uint ConstructorsCount
        {
            get
            {
                CheckingBasicTypes();
                return (uint)m_constructors.Count;
            }
        }

        public uint FunctionsCount
        {
            get
            {
                CheckingBasicTypes();
                return (uint)m_functions.Count;
            }
        }

        public uint ParametersCount
        {
            get
            {
                CheckingBasicTypes();
                return (uint)m_parameters.Count;
            }
        }

        public ConstructorField GetConstructorByIndex(uint n)
        {
            CheckingBasicTypes();
            if (n < m_constructors.Count)
            {
                return m_constructors[(int)n];
            }
            return null;
        }

        public FunctionField GetFunctionByIndex(uint n)
        {
            CheckingBasicTypes();
            if (n < m_functions.Count)
            {
                return m_functions[(int)n];
            }
            return null;
        }

        public ParameterField GetParameterByIndex(uint n)
        {
            CheckingBasicTypes();
            if (n < m_parameters.Count)
            {
                return m_parameters[(int)n];
            }
            return null;
        }

        /// <summary>
        /// Link on base class (object class return null)
        /// </summary>
        public ClassElement Base
        {
            get
            {
                CheckingBasicTypes();
                return m_base;
            }
        }

        public bool IsFinal
        {
            get
            {
                CheckingBasicTypes();
                return m_final;
            }
            set
            {
                CheckingBasicTypes();
                foreach (string str in m_basicTypesKeys)
                {
                    if (Name == str)
                    {
                        return;
                    }
                }
                m_final = value;
            }
        }

        public bool IsContains<T>(string name)
        {
            if (typeof(T) == typeof(FunctionField))
            {
                return IsContainsElement<FunctionField>(name, m_functions);
            }
            else if (typeof(T) == typeof(ParameterField))
            { 
                return IsContainsElement<ParameterField>(name, m_parameters);
            }
            return false;
        }

        public bool IsContainsConstructor(ConstructorField constructor)
        {
            foreach (ConstructorField cf in m_constructors)
            {
                if (cf.Signature.CompareTo(constructor.Signature) == 1)
                {
                    return true;
                }
            }
            return false;
        }

        private bool IsContainsElement<T>(string name, List<T> list) where T : FieldElement
        {
            foreach (T el in list)
            {
                if (el.Name == name)
                {
                    return true;
                }
            }
            return false;
        }
    }
}
